package org.opengauss;/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2012-2021. All rights reserved.
 */

import org.opengauss.driver.DriverInfoManager;
import org.opengauss.driver.IDriverInfo;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * description:this for Main Class
 * Copyright (c) Huawei Technologies Co., Ltd. 2012-2021.
 *
 * @author Administrator
 * @version [openGauss_debug 0.0.1 2021/3/9]
 * @since 2021/3/9
 */
public class NormalCreateConn {
    private static String usage() {
        String[] usages = { "This tools is to test multi connection:",
                "-h show this help."
        };
        return Arrays.stream(usages).collect(Collectors.joining("\n"));
    }
    
    public static class ArgsSelf {
        public int createThread = 100;
        public int connTimeoutThs = 500;
        public int testTime = 1 * 1000;
        public int testTimeWait = 1;
        public boolean showCreate = false;
    }
    
    public static String infoKey = null;
    public static ArgsSelf argsSelf = new ArgsSelf();
    public static CreateConn createConn = new CreateConn();
    public static class CreateConn {
        IDriverInfo info = (infoKey == null) ? DriverInfoManager.getInfo() : DriverInfoManager.getInfo(infoKey);
        public AtomicLong createNumber = new AtomicLong(0);
        public AtomicLong totalTime = new AtomicLong(0);
        public Queue<Long> overTotal = new ConcurrentLinkedQueue<>();
        public volatile long maxConnTime = 0;
        public volatile long maxConnIndex = 0;

        public volatile long minConnTime = 100000;
        public volatile long minConnIndex = 0;
        public Connection getConnection() throws SQLException  {
            long begin = System.currentTimeMillis();
            Connection conn =  DriverInfoManager.getConnection(info);
            long time = System.currentTimeMillis() - begin;
            long index = createNumber.incrementAndGet();
            totalTime.addAndGet(time);
            if (time > argsSelf.connTimeoutThs) {
                overTotal.add(time);
            }
            if (time > maxConnTime) {
                maxConnIndex = index;
                maxConnTime = time;
            }

            if (time < minConnTime) {
                minConnIndex = index;
                minConnTime = time;
            }
            if (argsSelf.showCreate) {
                Logger.info("index:" + index + " conn created:" + conn + ", time:" + time);
            } else {
                if (time > argsSelf.connTimeoutThs) {
                    Logger.info("index:" + index + " conn created:" + conn + ", time:" + time + " over threshold");
                }
            }
            return conn;
        }
    }
    
    public static class WorkThread extends Thread {
        public final ArgsSelf argsSelf;
        public CreateConn createConn;
        public WorkThread(ArgsSelf args, CreateConn createConn) {
            this.argsSelf = args;
            this.createConn = createConn;
        }
        
        @Override
        public void run() {
            long begin = System.currentTimeMillis();
            while (System.currentTimeMillis() - begin < argsSelf.testTime) {
                try (Connection conn = createConn.getConnection()) {
                    if (argsSelf.testTimeWait > 0 && argsSelf.testTimeWait < argsSelf.testTime) {
                        Thread.sleep(argsSelf.testTimeWait);
                    }
                } catch (SQLException sqlException) {
                    sqlException.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void initArgs(String[] args) {
//        public int createThread = 100;
//        public int connTimeoutThs = 500;
//        public int testTime = 30 * 1000;
//        public int testTimeWait = 1;
//        public boolean showCreate = false;
        argsSelf.createThread = Integer.parseInt(args[0]);
        argsSelf.connTimeoutThs = Integer.parseInt(args[1]);
        argsSelf.testTime = Integer.parseInt(args[2]);
        argsSelf.testTimeWait = Integer.parseInt(args[3]);
        argsSelf.showCreate = Integer.parseInt(args[4]) == 0 ? false : true;
    }
    public static void main(String ... args) throws IOException {
        Logger.info("input args format: thread threshold testTime connWait showlog");
        Logger.info("input args etc: 1 500 30000 1 0");
        String strArgs = Arrays.stream(args).collect(Collectors.joining(", "));
        Logger.info("input args:" + strArgs);
        initArgs(args);

//        org.opengauss.log.Slf4JLogger

        List<Thread> threads = IntStream.range(0, argsSelf.createThread).mapToObj(idx -> new WorkThread(argsSelf, createConn)).collect(Collectors.toList());
        threads.forEach(thd -> thd.start());
        
        threads.forEach(thd -> {
            try {
                thd.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    
        Logger.info("args:" + argsSelf);
        Logger.info("total create count:" + createConn.createNumber.get());
        Logger.info("total avg conn time:" + createConn.totalTime.get() / createConn.createNumber.get());
        Logger.info("max create time:" + createConn.maxConnTime + " index:" + createConn.maxConnIndex);
        Logger.info("min create time:" + createConn.minConnTime + " index:" + createConn.minConnIndex);
        Logger.info("total avg conn time:" + createConn.totalTime.get() / createConn.createNumber.get());
        Logger.info("over count=" + createConn.overTotal.size());
        Logger.info("over list:" + createConn.overTotal.stream().map(val -> "" + val).collect(Collectors.joining(",")));
        Logger.info("order over list:" + createConn.overTotal.stream().sorted().map(val -> "" + val).collect(Collectors.joining(",")));
    }
    
}
